package com.xiongtian.springframework.context.annotation;

import cn.hutool.core.util.StrUtil;
import com.xiongtian.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import com.xiongtian.springframework.beans.factory.config.BeanDefinition;
import com.xiongtian.springframework.beans.factory.support.BeanDefinitionRegistry;
import com.xiongtian.springframework.stereotype.Component;

import java.util.Set;

/**
 * @Author: xiongtian
 * @CreateTime: 2025-04-24  16:47
 * @Version: 1.0
 * @Description: 类路径扫描器
 * 扫描指定包下的类，将符合条件的类封装为 BeanDefinition，注册到 BeanDefinitionRegistry 中
 * 符合条件的类：
 * 1. 被 @Component 注解标注的类
 * 2. 被 @Scope 注解标注的类
 */

public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

    private BeanDefinitionRegistry registry;

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }


    /**
     * 扫描指定包下的类，将符合条件的类封装为 BeanDefinition，注册到 BeanDefinitionRegistry 中
     *
     * @param basePackages 指定包
     */
    public void doScan(String... basePackages) {
        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : candidates) {
                // 解析 Bean 的作用域 singleton、prototype
                String beanScope = resolveBeanScope(beanDefinition);
                if (StrUtil.isNotEmpty(beanScope)) {
                    beanDefinition.setScope(beanScope);
                }
                registry.registerBeanDefinition(determineBeanName(beanDefinition), beanDefinition);
            }
        }

        // 注册处理注解的 BeanPostProcessor（@Autowired、@Value）
        registry.registerBeanDefinition("com.xiongtian.springframework.context.annotation.internalAutowiredAnnotationProcessor", new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));
    }

    /**
     * 解析 Bean 的作用域
     * 1. 如果类上有 @Scope 注解，就使用 @Scope 注解的值
     * 2. 如果类上没有 @Scope 注解，就使用默认值 singleton
     *
     * @param beanDefinition Bean 定义
     * @return Bean 的作用域
     */
    private String resolveBeanScope(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getBeanClass();
        Scope scope = beanClass.getAnnotation(Scope.class);
        if (null != scope) return scope.value();
        return StrUtil.EMPTY;
    }

    /**
     * 确定 Bean 的名称
     * 1. 如果类上有 @Component 注解，就使用 @Component 注解的值
     * 2. 如果类上没有 @Component 注解，就使用类名的首字母小写
     *
     * @param beanDefinition Bean 定义
     * @return Bean 的名称
     */
    private String determineBeanName(BeanDefinition beanDefinition) {
        Class<?> beanClass = beanDefinition.getBeanClass();
        Component component = beanClass.getAnnotation(Component.class);
        String value = component.value();
        if (StrUtil.isEmpty(value)) {
            value = StrUtil.lowerFirst(beanClass.getSimpleName());
        }
        return value;
    }
}
